package org.gl.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import com.google.gson.Gson;
/**
 * NIO 实现的一个长连接持有池<br>
 * {@link#mSocketMap}
 * @author geliang
 * @time 2014/11/10
 *
 */
public class CameraProxyConnectPool {
	private static CameraProxyConnectPool mCameraProxyConnectPool;
	public final static int port = 1801;
	private static boolean isWorking = false;
	/**
	 * connect hash map
	 */
	HashMap<String, CameraProxy> mSocketMap = new HashMap<String, CameraProxy>();

	public HashMap<String, CameraProxy> getSocketMap() {
		return mSocketMap;
	}

	public synchronized static CameraProxyConnectPool getInstance() {
		if (mCameraProxyConnectPool == null) {
			mCameraProxyConnectPool = new CameraProxyConnectPool();
		}
		if (!isWorking) {
			new Thread() {
				public void run() {
					try {
						mCameraProxyConnectPool.start(port);
						isWorking = true;
					} catch (IOException e) {
						e.printStackTrace();
						isWorking = false;
					}
				};
			}.start();

		}
		return mCameraProxyConnectPool;
	}

	private ServerSocketChannel serverSocketChannel;
	private Selector selector;

	private CameraProxyConnectPool() {

	}
	/**
	 * inputsteam read thread 
	 */
	Thread ReceiveThread = new Thread() {
		public void run() {
			while (true) {
				try {
					sleep(10 * 1000);
					int readyChannels = selector.selectNow();
					if (readyChannels == 0)
						continue;
					Set<SelectionKey> selectedKeys = selector.selectedKeys();
					System.out.println("bind Client" + selector.keys().size());
					System.out.println("selectedKeys" + selectedKeys.size());
					Iterator<SelectionKey> keyIterator = selectedKeys
							.iterator();
					while (keyIterator.hasNext()) {
						SelectionKey key = keyIterator.next();
						if (key.isAcceptable()) {
							System.out.println("accept:");
						} else if (key.isConnectable()) {
							System.out.println("isConnectable:");
						} else if (key.isReadable()) {
							try {
								ByteBuffer buf = ByteBuffer.allocate(10 * 1024);
								int bytesRead;
								bytesRead = ((SocketChannel) key.channel())
										.read(buf);
								if (bytesRead > 0) {
									String contentg = new String(buf.array(),
											0, bytesRead);
									putCameraProxy2map(key, contentg);
								}
								buf.clear();
							} catch (IOException e) {
								e.printStackTrace();
							}
						} else if (key.isWritable()) {
							// a channel is ready for writing
							// System.out.println("isWritable:");
						}
						keyIterator.remove();
					}
				} catch (IOException e) {
					e.printStackTrace();
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}
			}

		}

		private void putCameraProxy2map(SelectionKey key, String contentg) {
			try {
				CameraProxy mCameraProxy = new Gson().fromJson(contentg,
						CameraProxy.class);
				if (mCameraProxy != null && mCameraProxy.getGUID() != null) {
					key.cancel();
					key.channel().configureBlocking(true);
					Socket mSocket = ((SocketChannel) key.channel()).socket();
					mCameraProxy.setSocket(mSocket);
					mSocketMap.put(mCameraProxy.getGUID()
							/*+ mCameraProxy.proxyCameraIP
							+ mCameraProxy.proxyCameraPort*//*only single channel*/, mCameraProxy);
					System.out.println("/*only single channel*/");
					System.out.println("camera pxory request sign up:"
							+ mCameraProxy.getGUID() + ",[ip:port]"
							+ mCameraProxy.getProxyCameraIP() + ":"
							+ mCameraProxy.getProxyCameraPort());
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		};
	};

	private void start(int port) throws IOException {

		serverSocketChannel = ServerSocketChannel.open();
		serverSocketChannel.socket().bind(new InetSocketAddress(port));
		serverSocketChannel.configureBlocking(true);

		selector = Selector.open();
		ReceiveThread.start();
		while (true) {
			SocketChannel clientChannle = serverSocketChannel.accept();
			// bind Channel to select
			clientChannle.configureBlocking(false);
			SelectionKey key = clientChannle.register(selector,
					SelectionKey.OP_READ | SelectionKey.OP_WRITE
							| SelectionKey.OP_CONNECT);
			// attach InetAddress to select
			key.attach(clientChannle.socket().getInetAddress());
			System.out.println("bind Client"
					+ clientChannle.socket().getInetAddress() + ":"
					+ clientChannle.socket().getPort());

		}

	}

	public void close() {
		if (serverSocketChannel != null) {
			try {
				serverSocketChannel.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		if (selector != null) {
			try {
				selector.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	static int i = 0;

	public static void main(String[] args) throws IOException,
			InterruptedException {
		CameraProxyConnectPool mCameraProxyConnectPool = CameraProxyConnectPool
				.getInstance();

		while (i < 1) {
			conncetClient();
			System.out.println("" + i);
			Thread.sleep(10);
			i++;
		}
		while (true)
			;
		// mCameraProxyConnectPool.close();
	}

	private static void conncetClient() {
		try {
			Socket mSocket = new Socket();
			mSocket.connect(new InetSocketAddress("192.168.2.22", 1801));

			// mSocket.connect(new InetSocketAddress("192.168.30.21", 5555));

			mSocket.getOutputStream().write(
					("{\"GUID\":\"88888888\"}").getBytes());
			mSocket.getOutputStream().flush();
			// mSocket.getOutputStream().close();
			byte s[] = new byte[1024];
			mSocket.getInputStream().read(s);
			System.out.println("" + new String(s));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
